/*
 * DeformacionCurvasBernstein.cpp
 *
 *  Created on: 23/04/2013
 *      Author: gonzalo
 */

#include "DeformacionCurvasBernstein.h"

DeformacionCurvasBernstein::DeformacionCurvasBernstein(GLuint cantidad_curvas,
		GLuint puntos_de_control_por_curva, GLfloat altura) :
		distribution(-altura, altura) {
	this->cant_curvas = cantidad_curvas;
	this->cant_puntos_de_control = puntos_de_control_por_curva;
	this->altura = altura;

	this->curvas_origen = new Casteljau[cantidad_curvas];
	this->curvas_destino = new Casteljau[cantidad_curvas];

	this->paso = 0;

	for (uint j = 0; j < cantidad_curvas; j++) {
		this->curvas_origen[j].add_control_point(glm::vec3(0, 2 * j / cantidad_curvas - 0.5, 0.0));
		this->curvas_destino[j].add_control_point(glm::vec3(0, 2 * j / cantidad_curvas - 0.5, 0.0));
	}

	for (uint j = 0; j < cantidad_curvas; j++) {
		for (uint i = 1; i < puntos_de_control_por_curva - 1; i++) {
			this->curvas_origen[j].add_control_point(
					glm::vec3(i / (puntos_de_control_por_curva - 1) - 0.5, 2 * j / cantidad_curvas - 0.5,
							0.0));
		}
	}

	for (uint j = 0; j < cantidad_curvas; j++) {
		for (uint i = 1; i < puntos_de_control_por_curva - 1; i++) {
			this->curvas_destino[j].add_control_point(
					glm::vec3(i / (puntos_de_control_por_curva - 1) - 0.5, 2 * j / cantidad_curvas - 0.5,
							distribution(generator)));
		}
	}
	for (uint j = 0; j < cantidad_curvas; j++) {
		this->curvas_origen[j].add_control_point(glm::vec3(0.5, 2 * j / cantidad_curvas - 0.5, 0.0));
		this->curvas_destino[j].add_control_point(glm::vec3(0.5, 2 * j / cantidad_curvas - 0.5, 0.0));
	}
	y_interpolado = -1;
}

DeformacionCurvasBernstein::~DeformacionCurvasBernstein() {
}

GLfloat DeformacionCurvasBernstein::obtener_deformacion(GLfloat x, GLfloat y) {

	if (y_interpolado != y) {
		curva_interpolante.clear_control_points();

		for (uint i = 0; i < cant_curvas; i++) {
			curva_interpolante.add_control_point(
					(1 - this->paso) * curvas_origen[i].get_point(x + 0.5)
							+ this->paso * curvas_destino[i].get_point(x + 0.5));
		}
	}

	return curva_interpolante.get_point(y + 0.5).z;
}

void DeformacionCurvasBernstein::set_velocidad_de_deformacion(GLfloat velocidad) {
	this->velocidad += velocidad;
}

void DeformacionCurvasBernstein::cambiar_curvas_deformacion() {
	Casteljau * aux;

	aux = curvas_origen;
	curvas_origen = curvas_destino;
	curvas_destino = aux;

	for (uint j = 0; j < cant_curvas; j++) {
		curvas_destino[j].clear_control_points();
		this->curvas_destino[j].add_control_point(glm::vec3(0, 2 * j / cant_curvas - 0.5, 0.0));
	}

	for (uint j = 0; j < this->cant_curvas; j++) {
		for (uint i = 1; i < this->cant_puntos_de_control - 1; i++) {
			this->curvas_destino[j].add_control_point(
					glm::vec3(i / (this->cant_puntos_de_control - 1) - 0.5, 2 * j / this->cant_curvas - 0.5,
							distribution(generator)));
		}
	}
	for (uint j = 0; j < cant_curvas; j++) {
		this->curvas_destino[j].add_control_point(glm::vec3(0.5, 2 * j / cant_curvas - 0.5, 0.0));
	}
}

void DeformacionCurvasBernstein::actualizar_deformacion() {
	if (this->paso < 1.0) {
		this->paso += velocidad;
		if (this->paso >= 1.0) {
			this->paso = 1.0;
		}
	} else {
		this->paso = this->velocidad;
		this->cambiar_curvas_deformacion();
	}
}

